package com.gsc.service.impl;

import com.gsc.constants.SystemConstants;
import com.gsc.domain.ResponseResult;
import com.gsc.domain.entity.LoginUser;
import com.gsc.domain.entity.User;
import com.gsc.domain.vo.BlogUserLoginVo;
import com.gsc.domain.vo.UserInfoVo;
import com.gsc.service.BlogLoginService;
import com.gsc.utils.BeanCopyUtils;
import com.gsc.utils.JwtUtil;
import com.gsc.utils.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.Objects;

/**
 * @author gscstart
 * @create 2023/2/2-16:55
 *
 *
 * 逻辑：使用security判断用户名和密码是否认证通过，如果认证通过，就会生成jwt，将“bloglogin”加userid生成key，loginUser为value存入到redis中
 */
@Service
public class BlogLoginServiceImpl implements BlogLoginService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;

    /**
     * 用户登录的实现方法
     * @param user
     * @return
     */
    @Override
    public ResponseResult login(User user) {
        UsernamePasswordAuthenticationToken authenticationToken
                = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());
        /*
            将用户名和密码封装好，传入到authenticate()方法中,在传到UserDetailsServiceImpl的方法中
            因为authenticationManager会调用UserDetailsService
         */
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        //做个安全性校验，判断是否认证通过
        if(Objects.isNull(authenticate)){
            throw new RuntimeException("用户名或密码错误");
        }
        //获取userid  生成token
            //LoginUser实现了UserDetails，还封装了user
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        String userid = loginUser.getUser().getId().toString();
        //token，（这里的token没有进行加密，可以解析得到用户id）
        String token = JwtUtil.createJWT(userid);
        //把用户信息存入redis
        redisCache.setCacheObject(SystemConstants.BOLG_KEY + userid,loginUser);
        //把token和userinfo封装 返回
            //把user转换成userInfoVo
        UserInfoVo userInfoVo = BeanCopyUtils.copyBean(loginUser.getUser(), UserInfoVo.class);
        BlogUserLoginVo vo = new BlogUserLoginVo(token,userInfoVo);
        return ResponseResult.okResult(vo);
    }

    /**
     * 退出登录实现方法
     * @return
     *
     * redis中的用户信息是由key-value组成的，首先要获取key（前缀+userid）
     * 可以从request对象中获取token，也可以从SecurityContextHolder中获取用户信息，在过滤器中已将用户信息存入SecurityContextHolder
     */
    @Override
    public ResponseResult logout() {

        //获取token 解析获取userid
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();

        //获取userid
        Long userId = loginUser.getUser().getId();

        //删除redis中的用户信息
            //优化：这里可以将"bloglogin"提取成常量
        redisCache.deleteObject("bloglogin:"+userId);

        return ResponseResult.okResult();
    }
}
